package dan.backend
import chisel3._
import chisel3.util._
import chisel3.util.experimental.decode.QMCMinimizer
import chisel3.util.experimental.decode.TruthTable
import dan.common._
import dan.common.Consts._
import dan.utility.ImplicitCast._
import dan.utility._
import dan.common.Instructions._
import dan.frontend.BrUpdateInfo

object DecodeLogic
{
  // TODO This should be a method on BitPat
  private def hasDontCare(bp: BitPat): Boolean = bp.mask.bitCount != bp.width
  // Pads BitPats that are safe to pad (no don't cares), errors otherwise
  private def padBP(bp: BitPat, width: Int): BitPat = {
    if (bp.width == width) bp
    else {
      require(!hasDontCare(bp), s"Cannot pad '$bp' to '$width' bits because it has don't cares")
      val diff = width - bp.width
      require(diff > 0, s"Cannot pad '$bp' to '$width' because it is already '${bp.width}' bits wide!")
      BitPat(0.U(diff.W)) ## bp
    }
  }

  def apply(addr: UInt, default: BitPat, mapping: Iterable[(BitPat, BitPat)]): UInt =
    chisel3.util.experimental.decode.decoder(QMCMinimizer, addr, TruthTable(mapping, default))
  def apply(addr: UInt, default: Seq[BitPat], mappingIn: Iterable[(BitPat, Seq[BitPat])]): Seq[UInt] = {
    val nElts = default.size
    require(mappingIn.forall(_._2.size == nElts),
      s"All Seq[BitPat] must be of the same length, got $nElts vs. ${mappingIn.find(_._2.size != nElts).get}"
    )
    //思路：将default转化为BitPat的形式，然后调用前面的apply函数来生成decoder
    val elementsGrouped = mappingIn.map(_._2).transpose
    val elementWidths = elementsGrouped.zip(default).map { case (elts, default) =>
      (default :: elts.toList).map(_.getWidth).max  //将default添加到列表的开头，最终得到一行元素中最大宽度，即每一个信号对应的宽度
    }
    val resultWidth = elementWidths.sum

    val elementIndices = elementWidths.scan(resultWidth - 1) { case (l, r) => l - r }

    // All BitPats that correspond to a given element in the result must have the same width in the
    // chisel3 decoder. We will zero pad any BitPats that are too small so long as they dont have
    // any don't cares. If there are don't cares, it is an error and the user needs to pad the
    // BitPat themselves
    val defaultsPadded = default.zip(elementWidths).map { case (bp, w) => padBP(bp, w) }
    val mappingInPadded = mappingIn.map { case (in, elts) =>
      in -> elts.zip(elementWidths).map { case (bp, w) => padBP(bp, w) }
    }
    val decoded = apply(addr, defaultsPadded.reduce(_ ## _), mappingInPadded.map { case (in, out) => (in, out.reduce(_ ## _)) })
    //返回译码结果
    elementIndices.zip(elementIndices.tail).map { case (msb, lsb) => decoded(msb, lsb + 1) }.toList
  }
  def apply(addr: UInt, default: Seq[BitPat], mappingIn: List[(UInt, Seq[BitPat])]): Seq[UInt] =
    apply(addr, default, mappingIn.map(m => (BitPat(m._1), m._2)).asInstanceOf[Iterable[(BitPat, Seq[BitPat])]])
  def apply(addr: UInt, trues: Iterable[UInt], falses: Iterable[UInt]): Bool =
    apply(addr, BitPat.dontCare(1), trues.map(BitPat(_) -> BitPat("b1")) ++ falses.map(BitPat(_) -> BitPat("b0"))).asBool
}

trait DecodeTable {
    val DC1 = BitPat.dontCare(1)
    def decode_default: List[BitPat] =
    //
    //       is val inst?                                             bypassable
    //       |    micro-code                       uses_ldg               |  is_br
    //       |    |  iq-type                       |  uses_stq            |  |
    //       |    |     |     func unit            |  |  is_ll            |  |  is_unique(clear pipeline for it)
    //       |    |     |      |     dst_type      |  |  |     is_dbar    |  |  |  flush_on_commit
    //       |    |     |      |     |    rs1_typ  |  |  | is_sc| is_ibar |  |  |  |
    //       |    |     |      |     |    |        |  |  |  |   |  |      |  |  |  |
    //       |    |     |      |     |    | rs2_typ|  |  |  |   |  |      |  |  |  |
    //       |    |     |      |     |    |    |   |  |  |  |   |  |      |  |  |  |
        List(N, UOP_X, IQT_X, FU_X, REGT_N, DC1, DC1, X, X, X, N,  X, N,     X, X, N, X)

    val table: Array[(BitPat, List[BitPat])]
}

class CtrlSigs extends Bundle {
    val legal           = Bool() //合法指令
    val uopc            = UInt(UOP_BITS.W) //指令对应的uop操作
    val iq_type         = UInt(IQT_BITS.W) //issue queue type
    val fu_code         = UInt(FU_BITS.W) //function code
    val dst_type        = UInt(1.W) //
    val rs1_type        = UInt(1.W) //
    val rs2_type        = UInt(1.W) //
    val uses_ldq        = Bool() //是否使用load
    val uses_stq        = Bool() //是否使用store
    val is_ll           = Bool()
    val is_sc           = Bool()
    val is_dbar         = Bool() //栅障指令
    val is_ibar         = Bool()
    val bypassable      = Bool() //rename中需要
    val is_br           = Bool() //
    val inst_unique     = Bool() //
    val flush_on_commit = Bool()
    def decode(instr: UInt, table: Iterable[(BitPat, List[BitPat])]) = {
        val decoder = DecodeLogic(instr, XDecode.decode_default, table)
        val sigs = Seq(
            legal, uopc, iq_type, fu_code, dst_type, rs1_type, rs2_type,
            uses_ldq, uses_stq, is_ll, is_sc, is_dbar, is_ibar,
            bypassable, is_br, inst_unique, flush_on_commit
        )
        sigs zip decoder map { case (s, d) => s := d }
        this
    }
}

object XDecode extends DecodeTable {
    val table: Array[(BitPat, List[BitPat])] = Array(
                //
                //    is val inst?                                                                     bypassable
                //        | micro-code                                           uses_ldg                  | is_br
                //        |    |           iq-type                                  | uses_stq             |  |
                //        |    |              |   func unit                         |  |  is_ll            |  | is_unique(clear pipeline for it)
                //        |    |              |       |    dst_type                 |  |  |     is_dbar    |  |  | flush_on_commit
                //        |    |              |       |       |    rs1_type         |  |  | is_sc| is_ibar |  |  |  |
                //        |    |              |       |       |       |             |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |    rs2_type |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |       |     |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |       |     |  |  |  |   |  |      |  |  |  |
        NEMU_TRAP -> List(Y, UOP_NOP      , IQT_INT, FU_X  , REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, N, N),

        LLW       -> List(Y, UOP_LLW      , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, Y, N,  N, N,     N, N, Y, Y),
        SCW       -> List(Y, UOP_SC_AG    , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_GPR, N, Y, N, Y,  N, N,     N, N, Y, Y),
        PRELD     -> List(Y, UOP_NOP      , IQT_MEM, FU_MEM, REGT_N  , REGT_GPR, REGT_N  , N, N, N, N,  N, N,     N, N, N, N),
        DBAR      -> List(Y, UOP_NOP      , IQT_INT, FU_X  , REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  Y, N,     N, N, N, N),
        IBAR      -> List(Y, UOP_NOP      , IQT_INT, FU_X  , REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, Y,     N, N, Y, Y),
        SRLIW     -> List(Y, UOP_SRLIW    , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        SRAIW     -> List(Y, UOP_SRAIW    , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        SRLW      -> List(Y, UOP_SRLW     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        SRAW      -> List(Y, UOP_SRAW     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        SLLIW     -> List(Y, UOP_SLLIW    , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        MODWU     -> List(Y, UOP_MODWU    , IQT_INT, FU_DIV, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        DIVWU     -> List(Y, UOP_DIVWU    , IQT_INT, FU_DIV, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        DIVW      -> List(Y, UOP_DIVW     , IQT_INT, FU_DIV, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        MODW      -> List(Y, UOP_MODW     , IQT_INT, FU_DIV, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        MULHWU    -> List(Y, UOP_MULHWU   , IQT_INT, FU_MUL, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        MULHW     -> List(Y, UOP_MULHW    , IQT_INT, FU_MUL, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        MULW      -> List(Y, UOP_MULW     , IQT_INT, FU_MUL, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, N, N),
        ORN       -> List(Y, UOP_ORN      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        ANDN      -> List(Y, UOP_ANDN     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        PCADDU12I -> List(Y, UOP_PCADDU12I, IQT_INT, FU_JMP, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        PCADDI    -> List(Y, UOP_PCADDI   , IQT_INT, FU_JMP, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        LU12IW    -> List(Y, UOP_LU12IW   , IQT_INT, FU_ALU, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        OR        -> List(Y, UOP_OR       , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        NOR       -> List(Y, UOP_NOR      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        LDW       -> List(Y, UOP_LD       , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, N, N,  N, N,     N, N, N, N),
        LDH       -> List(Y, UOP_LD       , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, N, N,  N, N,     N, N, N, N),
        LDHU      -> List(Y, UOP_LD       , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, N, N,  N, N,     N, N, N, N),
        LDB       -> List(Y, UOP_LD       , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, N, N,  N, N,     N, N, N, N),
        LDBU      -> List(Y, UOP_LD       , IQT_MEM, FU_MEM, REGT_GPR, REGT_GPR, REGT_N  , Y, N, N, N,  N, N,     N, N, N, N),
        STW       -> List(Y, UOP_STA      , IQT_MEM, FU_MEM, REGT_N  , REGT_GPR, REGT_GPR, N, Y, N, N,  N, N,     N, N, N, N),
        STH       -> List(Y, UOP_STA      , IQT_MEM, FU_MEM, REGT_N  , REGT_GPR, REGT_GPR, N, Y, N, N,  N, N,     N, N, N, N),
        STB       -> List(Y, UOP_STA      , IQT_MEM, FU_MEM, REGT_N  , REGT_GPR, REGT_GPR, N, Y, N, N,  N, N,     N, N, N, N),
        ADDIW     -> List(Y, UOP_ADDIW    , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        ANDI      -> List(Y, UOP_ANDI     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        ORI       -> List(Y, UOP_ORI      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        XORI      -> List(Y, UOP_XORI     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        SLTI      -> List(Y, UOP_SLTI     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        SLTUI     -> List(Y, UOP_SLTUI    , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
        SLLW      -> List(Y, UOP_SLLW     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        ADDW      -> List(Y, UOP_ADD      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        SUBW      -> List(Y, UOP_SUB      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        SLT       -> List(Y, UOP_SLT      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        SLTU      -> List(Y, UOP_SLTU     , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        AND       -> List(Y, UOP_AND      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        XOR       -> List(Y, UOP_XOR      , IQT_INT, FU_ALU, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, N, N),
        JIRL      -> List(Y, UOP_JIRL     , IQT_INT, FU_JMP, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     N, N, N, N),
        B         -> List(Y, UOP_BL       , IQT_INT, FU_JMP, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, N, N),
        BL        -> List(Y, UOP_BL       , IQT_INT, FU_JMP, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, N, N),
        BEQ       -> List(Y, UOP_BEQ      , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
        BNE       -> List(Y, UOP_BNE      , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
        BGE       -> List(Y, UOP_BGE      , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
        BGEU      -> List(Y, UOP_BGEU     , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
        BLT       -> List(Y, UOP_BLT      , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
        BLTU      -> List(Y, UOP_BLTU     , IQT_INT, FU_ALU, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, Y, N, N),
    )
}

object TLBDeocde extends DecodeTable {
   val table: Array[(BitPat, List[BitPat])] = Array(
               //
               //    is val inst?                                                                      bypassable
               //        | micro-code                                             uses_ldg                 | is_br
               //        |    |           iq-type                                   | uses_stq             |  |
               //        |    |              |   func unit                          |  |  is_ll            |  | is_unique(clear pipeline for it)
               //        |    |              |       |    dst_type                  |  |  |     is_dbar    |  |  | flush_on_commit
               //        |    |              |       |       |    rs1_type          |  |  | is_sc| is_ibar |  |  |  |
               //        |    |              |       |       |       |              |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |    rs2_type  |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
        TLBSRCH  -> List(Y, UOP_TLBSRCH   , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        TLBFILL  -> List(Y, UOP_TLBFILL   , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        TLBRD    -> List(Y, UOP_TLBRD     , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        TLBWR    -> List(Y, UOP_TLBWR     , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB0  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB1  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB2  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB3  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB4  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB5  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
        INVTLB6  -> List(Y, UOP_INVTLB    , IQT_INT, FU_CSR, REGT_N  , REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     N, N, Y, Y),
    )
}

object CSRDecode extends DecodeTable {
    val table: Array[(BitPat, List[BitPat])] = Array(
                //
                //    is val inst?                                                                     bypassable
                //        | micro-code                                           uses_ldg                  | is_br
                //        |    |           iq-type                                  | uses_stq             |  |
                //        |    |              |   func unit                         |  |  is_ll            |  | is_unique(clear pipeline for it)
                //        |    |              |       |    dst_type                 |  |  |     is_dbar    |  |  | flush_on_commit
                //        |    |              |       |       |    rs1_type         |  |  | is_sc| is_ibar |  |  |  |
                //        |    |              |       |       |       |             |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |    rs2_type |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |       |     |  |  |  |   |  |      |  |  |  |
                //        |    |              |       |       |       |       |     |  |  |  |   |  |      |  |  |  |
        CSRRD     -> List(Y, UOP_CSRRD    , IQT_INT, FU_CSR, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRWR     -> List(Y, UOP_CSRWR    , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_N  , N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG1  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG2  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG3  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG4  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG5  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG6  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG7  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG8  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG9  -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG10 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG11 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG12 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG13 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG14 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        CSRXCHG15 -> List(Y, UOP_CSRXCHG  , IQT_INT, FU_CSR, REGT_GPR, REGT_GPR, REGT_GPR, N, N, N, N,  N, N,     Y, N, Y, Y),
        ERTN      -> List(Y, UOP_ERET     , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        SYSCALL   -> List(Y, UOP_ERET     , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        BREAK     -> List(Y, UOP_ERET     , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
    )
}

object CntDecode extends DecodeTable {
   val table: Array[(BitPat, List[BitPat])] = Array(
               //
               //    is val inst?                                                                      bypassable
               //        | micro-code                                              uses_ldg                | is_br
               //        |    |           iq-type                                   | uses_stq             |  |
               //        |    |              |   func unit                          |  |  is_ll            |  | is_unique(clear pipeline for it)
               //        |    |              |       |    dst_type                  |  |  |     is_dbar    |  |  | flush_on_commit
               //        |    |              |       |       |    rs1_type          |  |  | is_sc| is_ibar |  |  |  |
               //        |    |              |       |       |       |              |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |    rs2_type  |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
       RDTIMELW  -> List(Y, UOP_RDTIMELW  , IQT_INT, FU_CNT, REGT_GPR, REGT_N  , REGT_N  , N ,N, N, N,  N, N,     Y, N, N, N),
       RDCNTVHW  -> List(Y, UOP_RDCNTVHW  , IQT_INT, FU_CNT, REGT_GPR, REGT_N  , REGT_N  , N, N, N, N,  N, N,     Y, N, N, N),
   )
}

object WeirdDecode extends DecodeTable {
   val table: Array[(BitPat, List[BitPat])] = Array(
               //
               //    is val inst?                                                                      bypassable
               //        | micro-code                                            uses_ldg                  | is_br
               //        |    |           iq-type                                   | uses_stq             |  |
               //        |    |              |   func unit                          |  |  is_ll            |  | is_unique(clear pipeline for it)
               //        |    |              |       |    dst_type                  |  |  |     is_dbar    |  |  | flush_on_commit
               //        |    |              |       |       |    rs1_type          |  |  | is_sc| is_ibar |  |  |  |
               //        |    |              |       |       |       |              |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |    rs2_type  |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
               //        |    |              |       |       |       |       |      |  |  |  |   |  |      |  |  |  |
        IDLE     -> List(Y, UOP_IDLE      , IQT_INT, FU_CSR, REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, N,     N, N, Y, Y),
        // now cacop is as same as ibar
        CACOP    -> List(Y, UOP_NOP       , IQT_INT, FU_X  , REGT_N  , REGT_N  , REGT_N  , N, N, N, N,  N, Y,     N, N, Y, Y),
   )
}

class DecodeUnitIO() extends CoreBundle {
    val enq = new Bundle { val uop = Input(new UOp()) }
    val deq = new Bundle { val uop = Output(new UOp()) }
    val interrupt = Input(Bool())
}

//TODO 添加对CSR环境下异常指令的检测
class DecodeUnit extends CoreModule {
    val io = IO(new DecodeUnitIO)

    val uop = Wire(new UOp)
    uop := io.enq.uop

    var decode_table = XDecode.table
    decode_table ++= CSRDecode.table
    decode_table ++= CntDecode.table
    decode_table ++= TLBDeocde.table
    decode_table ++= WeirdDecode.table

    val inst = uop.instr
    val cs = Wire(new CtrlSigs).decode(inst, decode_table)

    val id_illegal_insn = !cs.legal
    val xcpt_valid = WireInit(false.B)
    val xcpt_cause = WireInit(0.U(ExpCode.microExpBits.W))

    when (io.interrupt) {
        xcpt_valid := true.B
        xcpt_cause := ExpCode.INT
    } .elsewhen (io.enq.uop.expValid) {
        xcpt_valid := true.B
        xcpt_cause := io.enq.uop.expCause
    } .elsewhen (inst === SYSCALL || inst === BREAK) {
        when (inst === SYSCALL) {
            xcpt_valid := true.B
            xcpt_cause := ExpCode.SYS
        } .otherwise {
            xcpt_valid := true.B
            xcpt_cause := ExpCode.BRK
        }
    } .elsewhen (id_illegal_insn) {
        xcpt_valid := true.B
        xcpt_cause := ExpCode.INE
    }

    uop.memSize := inst(23, 22)
    uop.memSigned := !inst(25)
    uop.tlbOp := inst(4, 0)
    uop.useLdQ := cs.uses_ldq
    uop.useStQ := cs.uses_stq
    uop.isLL := cs.is_ll
    uop.isSC := cs.is_sc
    uop.isDbar := cs.is_dbar
    uop.isIbar := cs.is_ibar
    uop.isUnique := cs.inst_unique
    uop.flushIfCommit := cs.flush_on_commit
    uop.bypassable := cs.bypassable
    uop.formatImm := inst(25, 0)
    uop.isBr := cs.is_br
    uop.isJal := cs.uopc === UOP_BL
    uop.isJalr := cs.uopc === UOP_JIRL
    uop.uopType := cs.uopc
    uop.iqType := cs.iq_type
    uop.fuType := cs.fu_code
    uop.archDst := inst(4, 0)
    uop.archOprand1 := inst(9, 5)
    uop.archOprand2 := inst(14, 10)
    uop.vaWrEnable := false.B

    when(xcpt_valid && (xcpt_cause === ExpCode.PIF || xcpt_cause === ExpCode.PPI || xcpt_cause === ExpCode.ADEF || xcpt_cause === ExpCode.TLBR)){
        uop.vaWrEnable := true.B
    }
    uop.expValid := xcpt_valid
    uop.expCause := xcpt_cause
    //-------------------------------------------------------------

    when (cs.uopc === UOP_BL) {
        uop.archDst := 1.U
    }
    when (cs.uopc === UOP_RDTIMELW && inst(4,0) === 0.U) {
        uop.uopType            := UOP_RDCNTIDW
        uop.fuType          := FU_CSR
        uop.archDst            := inst(9, 5)
        uop.isUnique       := true.B
        uop.flushIfCommit := true.B
    } .elsewhen (cs.uopc === UOP_RDTIMELW) {
        uop.uopType := UOP_RDCNTVLW
    }
    when (cs.uopc === UOP_LLW || cs.uopc === UOP_SC_AG) {
        uop.memSize := 2.asUInt
    }
    when (
        (uop.uopType === UOP_BEQ || uop.uopType === UOP_BNE || uop.uopType === UOP_BGE || uop.uopType === UOP_BGEU || uop.uopType === UOP_BLT || uop.uopType === UOP_BLTU) ||
        (uop.uopType === UOP_STA || uop.uopType === UOP_SC_AG)
    ) {
        uop.archOprand2 := inst(4, 0)
    }
    when (cs.uopc === UOP_CSRWR || cs.uopc === UOP_CSRXCHG) {
        uop.archOprand1 := inst(4, 0)
        uop.archOprand2 := inst(9, 5)
    }
    uop.archDstValid   := cs.dst_type =/= REGT_N && uop.archDst =/= 0.U
    uop.archDstType  := cs.dst_type
    uop.archOp1Type := cs.rs1_type
    uop.archOp2Type := cs.rs2_type

    /* when (cs.uopc === uopORI && inst(21,10) === 0.U) {
        uop.uopType := uopMOV
    }*/
    when (cs.uopc === UOP_ADDIW && inst(21, 0) === 0.U) {
        uop.uopType := UOP_NOP
    }

    io.deq.uop  := uop
}

class BrMaskUnit extends CoreModule {
    val io = IO(new Bundle {
        val is_branch = Input(Vec(coreWidth, Bool()))
        val will_fire = Input(Vec(coreWidth, Bool()))
        val br_tag    = Output(Vec(coreWidth, UInt(log2Ceil(maxBrNum).W)))
        val br_mask   = Output(Vec(coreWidth, UInt(maxBrNum.W)))
        val is_full   = Output(Vec(coreWidth, Bool()))
        val br_update = Input(new BrUpdateInfo)
        val flush     = Input(Bool())
    })

    val branch_mask = RegInit(0.U(maxBrNum.W))

    var allocate_mask = branch_mask
    val tag_masks = Wire(Vec(coreWidth, UInt(maxBrNum.W)))
    for (w <- 0 until coreWidth) {
        io.is_full(w) := (allocate_mask === (~0.U(maxBrNum.W)).asUInt) && io.is_branch(w)

        // find br_tag and compute next br_mask
        val new_br_tag = Wire(UInt(log2Ceil(maxBrNum).W))
        new_br_tag   := 0.U
        tag_masks(w) := 0.U

        for (i <- maxBrNum - 1 to 0 by -1) {
            when (!allocate_mask(i)) {
                new_br_tag   := i.U
                tag_masks(w) := (1.U << i.U)
            }
        }

        io.br_tag(w) := new_br_tag
        allocate_mask = Mux(io.is_branch(w), tag_masks(w) | allocate_mask, allocate_mask)
    }

    var curr_mask = branch_mask
    for (w <- 0 until coreWidth) {
        io.br_mask(w) := UpdatedBrMask(curr_mask, io.br_update)
        curr_mask = Mux(io.will_fire(w), tag_masks(w) | curr_mask, curr_mask)
    }

    when (io.flush) {
        branch_mask := 0.U
    } .otherwise {
        val mask = Mux(
            io.br_update.resolInfo.mispredict, io.br_update.resolInfo.uop.brMask,
                                        (~0.U(maxBrNum.W)).asUInt
        )
        branch_mask := UpdatedBrMask(curr_mask, io.br_update) & mask
    }
}

